#pragma once

#include "CriticalSection.h"
#include "ScopedLock.h"
#include <list>

template <typename T>
class GuardedList
{
public:
	GuardedList() {};
	~GuardedList() {};
	
	void assign(size_t _Count, const T& _Val)
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.assign(_Count, _Val);
	};

	T& back() const
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		return m_list.back();
	}

	const T& back() const
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		return m_list.back();
	}

	void clear( )
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.clear();
	}

	bool empty( ) const
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		return m_list.empty();
	}

	T& front( ) const
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		return m_list.front();
	}

	const T& front( ) const
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		return m_list.front();
	}

	size_t max_size( ) const
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		return m_list.max_size();
	}

	void merge(std::list<T>& _Right)
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.merge(_Right);
	}

	template<class Traits>
	void merge(std::list<T>& _Right, Traits _Comp)
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.merge<_Comp>(_Right);
	}
	
	void pop_back()
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.pop_back();
	}

	void pop_front()
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.pop_front();
	}

	void push_back(const T& _Val)
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.push_back(_Val);
	}

	void push_front(const T& _Val)
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.push_front(_Val);
	}

	void remove(const T& _Val)
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.remove(_Val);
	}

	template<class Predicate> 
	void remove_if(Predicate _Pred)
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.remove_if(_Pred);
	}

	void resize(size_t _Newsize)
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.resize(_Newsize);
	}

	void resize(size_t _Newsize, T _Val)
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.resize(_Newsize, _Val);
	}

	void sort()
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.sort();
	}

	template<class Traits> 
	void sort(Traits _Comp)
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.sort(_Comp);
	}

	void swap(std::list<T>& _Right)
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.swap(_Right);
	}

	void unique()
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.unique();
	}

	template<class BinaryPredicate>
	void unique(BinaryPredicate _Pred)
	{
		ScopedLock<CriticalSection> lock(m_criticalSection);
		m_list.unique(_Pred);
	}

	std::list<T>& LockList() const 
	{ 
		m_criticalSection.Lock();
		return m_list; 
	}

	void UnlockList() const
	{
		m_criticalSection.Unlock();
	}
private:
	std::list<T> m_list;
	CriticalSection m_criticalSection;
};

